home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / docs / gccfaq10 / gccfaq10.txt < prev    next >
Encoding:
Text File  |  1995-02-15  |  11.1 KB  |  348 lines

  1. DJGPP DOS GAME PROGRAMMERS FAQ V1.0
  2. ___________________________________
  3.  
  4. The intention of this FAQ is to provide the basic technical information 
  5. required to do all the good stuff that you can do with other DOS based
  6. compilers. It shows how to access most hardware such as video, sound,
  7. controllers, timers, interrupts under various OS's like DOS, Windows,
  8. OS/2. (though in a DOS session)
  9.  
  10. This FAQ does not show you how to write games, nor is it a library
  11. of functions, though it will hopefully provide enough information for 
  12. most people with programming experience to convert one of the many 
  13. existing libraries available for other compilers.
  14.  
  15. I am open to corrections, improvements and expansion of this FAQ. A lot
  16. of this information has come from my own experimentation with the 
  17. compiler and hardware.
  18.  
  19. I hope you find it useful. Let me know how y'all get on!
  20.  
  21. S.Hull@bradford.ac.uk
  22. Stu Hull.
  23. _______________________________________________________________________
  24.  
  25. Q. What is DGJPP?
  26.  
  27. DGJPP is a popular port of GNU C by DJ Delorie. It is a full 32-bit
  28. compiler with DOS extender with a flat memory model, and can access
  29. 128Mb of physical and 128Mb of Virtual (Disk swapped) memory. It is
  30. distributed under the GNU Licence agreement. It currently has no
  31. development environment (provide your own text editors!) and only a
  32. basic debugger, these aside it is a very competent compiler.
  33.  
  34. Q. Where can I get DJGPP?
  35.  
  36. Any SimTel site. Try oak.oakland.edu:/pub/msdos/djgpp. Pull the faq in 
  37. the directory which will explain the minimum files required, and the
  38. basics of operation.
  39.  
  40. Q. How do I install DJGPP?
  41.  
  42. Create a directory (example C:\GCC) and unzip the files required (don't 
  43. forget the -d switch to build directories), then add the following
  44. statement to your autoexec file:
  45.  
  46.   SET DJGPP=C:\GCC\DJGPP.ENV
  47.   and add C:\GCC\BIN to your PATH statement.
  48.  
  49. Q. Can I distribute programs compiled with DJGPP?
  50.  
  51. That would appear to depend upon which libraries you use. As far as I
  52. understand it none of the following examples use library code that 
  53. cannot be distributed, and go32 is public domain, but please check 
  54. before releasing. If you are making a commercial release it is 
  55. suggested you make an appropriate donation to the developers.
  56.  
  57. Q. How do I compile/link/include libraries?
  58.  
  59. Briefly, without going into things like makefiles, there are two 
  60. steps, compile into object (COFF format) and link. A few examples
  61. follow:
  62.  
  63. To compile and link (to 'a.out'):
  64.  
  65.   gcc [options] {sourcename} [-l{libname}]
  66.  
  67. Compile (to object):
  68.   gcc [options] {sourcename} -o {objectname}
  69.  
  70. Link (to 'a.out'):
  71.   ld \gcc\lib\crt0.o -L\gcc\lib {objectname(s)} -lgcc -lc [-l{libname}]
  72.  
  73. Useful compile options include:
  74.   -Wall  All warning messages displayed.
  75.   -m486  Optimise for 486.
  76.  
  77. Q. How do I execute ('a.out')?
  78.   
  79.   go32 a.out [arguments]
  80.  
  81. Q. How do I start the debugger?
  82.  
  83. # go32 -d edebug32 a.out [arguments]
  84. (or use ed32-dpmi if running under Windows/OS2 etc).
  85.  
  86. Q. How do I use the inline assembler?
  87.  
  88. As you may know, the format used by the GNU assembler differs from
  89. what Intel uses. Inline assembly is encapsulated with 'asm("...")'
  90. inside your c code. Follow these rules and you'll be OK:
  91.  
  92. Typical format is:
  93.   {instruction} {source}, {dest}    (NOT {dest}, {source}!)
  94.  
  95. Each instruction is suffixed with the operation size (though this
  96. can also be assumed from the register size) such as 'b' for byte,
  97. 'w' for word, 'l' for long word.
  98.  
  99. Registers are prefixed with a '%'.
  100.  
  101. Numbers are prefixed with '$' and assumed to be decimal unless they
  102. are of the '0x' format.
  103.  
  104. Indirect addressing is done by surrounding the term with brackets
  105. (eg '(%esi)', or '%es:(%edi)' with segment prefix).
  106.  
  107. Variables are prefixed with _ (underscore) though they cannot be
  108. local to the procedure (ie they must be defined globally). To 
  109. access external global variables, you must also surround the name
  110. with brackets to access it indirectly.
  111.  
  112. Instructions can be separated with newline or ';'.
  113.  
  114. Examples:
  115.   asm("
  116.    pushw %es
  117.    movw (_DosSeg), %es
  118.    movl _offset, %edi
  119.    movl $4, %eax
  120.    movb %al, %es:(%edi)
  121.   
  122.    rep ; movsl
  123.   
  124.   moveloop:
  125.    decl %ecx
  126.    jnz  memloop
  127.   ");
  128.  
  129. Q. Why are segments registers still used with a flat memory model?
  130.  
  131. Without going into too much detail about protected mode environments,
  132. there are no segments as such, but selectors, although they can be
  133. treated in a similar fashion. When running in protected mode DOS
  134. memory is assigned a selector, and your code another. This means that
  135. no matter what address your code tries to access it will not interfere
  136. with the DOS memory, or any other memory it hasn't been given access
  137. to. This is the mechanism used by a 32-bit OS preventing one from
  138. accessing another.
  139.  
  140. This creates problems when accessing Video memory in the DOS segment.
  141. 'go32' will try to re-map some area's of memory to appear as the DOS
  142. memory, though under a 32-bit OS it cannot do this. There are ways 
  143. round this though which I will deal with later.
  144.  
  145. Q. How do I select graphics modes?
  146.  
  147. This is the same as real mode, for example to set mode 13h 
  148. (include <dos.h>):
  149.  
  150.   union REGS in, out;
  151.  
  152.   in.x.ax = 0x0013; 
  153.   int86(0x10, &in, &out);
  154.  
  155. Q. How to I set mode-x?
  156.  
  157. Again, this is the same as for real mode.
  158.  
  159.    [Set mode 13h, as above]
  160.  
  161.    /* Unchain */
  162.  
  163.    outportw(0x3c4, 0x0604);
  164.    outportw(0x3d4, 0xe317);
  165.    outportw(0x3d4, 0x0014);
  166.  
  167.    /* Enable all planes */
  168.  
  169.    outportw(0x3c4, 0x0f02);
  170.  
  171. Q. How is DOS/video memory accessed?
  172.  
  173. You could use one of the graphics libraries provided which are intended 
  174. to make it easier to port code written for other systems, unfortunately 
  175. they do not work in a protected mode environment (Such as Windows and
  176. OS2) and are slow.
  177.  
  178. Your code does not automatically have access to DOS memory, though the
  179. dosmemput and dosmemget functions will do this for you, example:
  180.  
  181.    dosmemput("H.e.l.l.o.", 10, 0xb8000);
  182.  
  183. will put 'Hello' in the top left hand corner of a text screen (don't
  184. forget to include <pc.h>, <dos.h> and use add the library -lpc).
  185.  
  186. If you want to access it yourself via asm you need to find out what
  187. the DOS selector is (selectors are explained elsewhere), and load
  188. this into a segment register. The same example with inline asm:
  189.   
  190.   #include <go32.h>
  191.    
  192.   static int dos_seg, length;
  193.   static char *string;
  194.  
  195.   main()
  196.   {
  197.   dos_seg = _go32_conventional_mem_selector();
  198.   string  = "H.e.l.l.o.";
  199.   length  = 10;
  200.  
  201.   asm ("
  202.    pushw %es
  203.  
  204.    movw  _dos_seg, %es
  205.  
  206.    movl  _string, %esi
  207.    movl  $0xb8000, %edi
  208.   
  209.    movw  _length, %cx
  210.  
  211.    rep ; movsb 
  212.  
  213.    popw  %es
  214.   ");
  215.   }
  216.  
  217. Q. How do I detect available physical/virtual memory?
  218.  
  219. The following functions are provided (include <dpmi.h>):
  220.  
  221.   _go32_dpmi_remaining_physical_memory();
  222.   _go32_dpmi_remaining_virtual_memory();
  223.  
  224. Q. How are floating point numbers handled?
  225.  
  226. By default, DJGPP uses the maths co-processor found on some systems.
  227. There is an emulator but you must include it your self. I have yet
  228. to evaluate this.
  229.  
  230. Q. How do I chain interrupts?
  231.  
  232. You must provide the offset and selector for the function to be 
  233. chained. For example, chaining the hardware timer interrupt:
  234.  
  235.   #include <go32.h>
  236.  
  237.   void Interrupt(void)
  238.   {
  239.    /* Timer interrupt handler */
  240.   }
  241.  
  242.   main()
  243.   {
  244.    _go32_dpmi_seginfo old_handler, new_handler;
  245.  
  246.    new_handler.pm_offset   = (int) Interrupt;
  247.    new_handler.pm_selector = _go32_my_cs();
  248.  
  249.    _go32_dpmi_get_protected_mode_interrupt(8, &old_handler);
  250.    _go32_dpmi_chain_protected_mode_interrupt(8, &new_handler);
  251.  
  252.    /* Interrupt is chained */
  253.  
  254.    _go32_dpmi_set_protected_mode_interrupt(8, &old_handler);
  255.  
  256.    /* Interrupt is unchained */
  257.   }
  258.  
  259. NOTE: There is a problem when running under DOS however, when you
  260. get the old interrupt offset/selector you get a bogus value. If you 
  261. then use this to unchain the interrupt, and later another interrupt
  262. does occur, you program will crash. I need to find out if there is
  263. a fix for this. At the moment, I unchain and immediately exit to 
  264. prevent a crash if run under DOS.
  265.  
  266. There are also problems under OS/2 and Win which I mention in the 
  267. sound card DMA example. Either interrupt chaining is buggy or I am
  268. doing something wrong. I would like to know.
  269.  
  270. Q. How do I access the FM part of a soundcard?
  271.  
  272. Since all FM access can be done with hardware ports this is the 
  273. same as in real mode.
  274.  
  275. Q. How do I play digital sounds via DMA?
  276.  
  277. This is probably the least well documented subject in the PC world,
  278. so I have included in the examples some code to play mono .WAV files
  279. of any length. The following is a description of how it is done:
  280.  
  281. The basic idea goes like this, you set up a DOS memory buffer for 
  282. the DMA transfer, any size, but tell the sound card it will be the
  283. full 64Kb. You then tell the DMA to transfer the buffer in cycle
  284. mode, which basically resends the same chunk of memory all the time.
  285. When the sound card creates and interrupt to say 64Kb has been
  286. transferred, you tell it to take another 64Kb. This way DMA does
  287. not have to be set up again, and reduces clicking to almost
  288. non existent.
  289.  
  290. To play a sound bigger than the buffer size you need to keep a
  291. track of where the DMA transfer is, and while one half is being
  292. played, fill the other half with the next part of the sound. The
  293. buffer must also be filled with silence in-between samples. The
  294. example chains the hardware timer to do this.
  295.  
  296. When writing this code I noticed a problem which I call interrupt
  297. miss. Sometimes you don't get a timer interrupt or sound card
  298. interrupt in protected mode. The program only seems to get 
  299. notified of an interrupt if it occurs while the processor is 
  300. executing your segment. Do a function like printf, which runs
  301. in the DOS segment, and you will not get notified.
  302.  
  303. To prevent this being a problem with the DMA code I have done
  304. two things, made the buffer large enough to tolerate a timer
  305. interrupt miss before the sound becomes looped, and also made
  306. the code that reads the DMA count make sure the it has changed
  307. since last time, otherwise the DMA transfer is restarted.
  308.  
  309. There was a problem with OS/2 2.1 that prevented the DMA from
  310. being in cycle mode, though it would work with the DMA transfer
  311. detection above would sound choppy, though this seems to have
  312. been put right in OS/2 WARP.
  313.  
  314. Allocation of DOS memory for a DMA buffer:
  315.  
  316.   int AllocateBuffer()
  317.   {
  318.   unsigned int address, page;
  319.   _go32_dpmi_seginfo memory;
  320.  
  321.   /* Allocate memory, return zero if fails */
  322.  
  323.   memory.size = (DMA_SIZE * 2) / 16;
  324.   if (_go32_dpmi_allocate_dos_memory(&memory)) return(0);
  325.  
  326.   /* What is the 20 bit address? */
  327.  
  328.   address = memory.rm_segment << 4;
  329.  
  330.   /* Does it cross a 64K boundary? */
  331.  
  332.   page = address & 0xffff;
  333.   if ((page + DMA_SIZE) > 0xffff) address = (address - page) + 0x10000;
  334.  
  335.   /* Return the address of the buffer */
  336.  
  337.   return(address);
  338.   }
  339.  
  340. Q. How do I write a keyboard handler?
  341. There may be a problem with interrupt miss though I haven't tried 
  342. this yet. Still in progress.
  343.  
  344. Q. How do I read from mouse?
  345. There is a library of functions available, and these may be good 
  346. for cross platform compatibility, but the usual 'int86()' calls
  347. will work fine.
  348.